/*
 * @Author: linxun 
 * @Date: 2021-08-11 14:34:24 
 * @Last Modified by: linxun
 * @Last Modified time: 2021-08-24 15:49:01
 * @Description: 数据集查看文件目录
 */

import React, { useEffect, useState } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Card, Tree, Empty, message } from 'antd';
import { connect, useIntl, history } from 'umi';
import { getFileDirectory, getFile } from '../service';
import { throttle, getFileSuffix } from '@/utils/utils';
import { MoreOutlined } from '@ant-design/icons';
import useKeyPress from '@/utils/useKeyPress';
import ImageViewer from './components/Image';
import FileViewer from './components/File';

import type { ConnectProps, Dispatch } from 'umi';

import styles from './index.less';

const IMAGE_SUFFIX = ['jpg', 'png', 'jpeg'];

interface Props extends ConnectProps {
  dispatch: Dispatch;
}

interface DataNode {
  title: string;
  key: string;
  isLeaf?: boolean;
  children?: DataNode[];
}

type FileType = 'directory' | 'image' | 'file';

const updateTreeData = (list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] => {
  return list.map(node => {
    if (node.key === key) {
      return {
        ...node,
        children,
      };
    }
    if (node.children) {
      return {
        ...node,
        children: updateTreeData(node.children, key, children),
      };
    }
    return node;
  });
};

const getPathByKey = (list: DataNode[], key: React.Key) => {
  const keys = key.toString().split('-');
  keys.pop();
  let result = '';
  const getTitle = (children: DataNode[], index: number) => {
    result += `/${children[index]?.title}`;
  };
  keys.forEach(i => {
    getTitle(list, Number(i));
  });
  return result;
};

const getChildrenByKey = (list: DataNode[], key: React.Key) => {
  let result: DataNode[] = [];
  let node;
  for (let i = 0; i < list.length; i++) {
    node = list[i];
    if (node.key === key) {
      result = node?.children || [];
      break;
    }
    if (node.children) {
      const res: DataNode[] = getChildrenByKey(node.children, key);
      if (res && res.length) return res;
    }
  }
  return result;
};

const getSameLevelFilesByKey = (list: DataNode[], key: React.Key) => {
  const keys = (key).toString().split('-');
  keys.pop();
  if (keys.length) {
    return getChildrenByKey(list, keys.join('-'))?.filter(i => i.isLeaf && !i.key?.includes('9999'));
  }
  return list?.filter(i => i.isLeaf && !i.key?.includes('9999'));
};

const Files: React.FC<Props> = (props) => {
  const { formatMessage: f } = useIntl();
  const { dispatch, match } = props;
  const { id: dataSetId } = match?.params as { id: string };

  const leftPress = useKeyPress('ArrowLeft');
  const rigthPress = useKeyPress('ArrowRight');

  const [directoryData, setDirectoryData] = useState<DataNode[]>([]);
  const [newData, setNewData] = useState([]);
  const [maxHeight, setMaxHeight] = useState(800);
  const [curFileType, setCurFileType] = useState<FileType>('directory');
  const [curFile, setCurFile] = useState({});
  const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
  const [curSameLevelFiles, setCurSameLevelFiles] = useState<DataNode[]>([]);

  const fetchDirectory = async (path: string) => {
    try {
      const res = await getFileDirectory(dataSetId, path);
      if (res && res.code === 0) {
        if (!path) {
          const data: any[] = res.data?.items?.map((i: any, index: number) => ({
            title: i.name,
            key: `${index}`,
            selectable: !i.isDirectory,
            isLeaf: !i.isDirectory,
          }));
          setDirectoryData(data.concat(res.data?.isComplete ? [] : [{
            title: '......',
            key: '9999',
            selectable: false,
            isLeaf: true,
            switcherIcon: <MoreOutlined />,
          }]));
          // selectFirstFile(data);
        } else {
          const newData = res.data?.items?.map((i: any) => ({
            title: i.name,
            selectable: !i.isDirectory,
            isLeaf: !i.isDirectory,
          })).concat(res.data?.isComplete ? [] : [{
            title: '......',
            key: '9999',
            selectable: false,
            isLeaf: true,
            switcherIcon: <MoreOutlined />,
          }]);
          return new Promise<void>(resolve => {
            resolve(newData);
          })
        }
      }
    } catch (err) {
      console.log(err);
    }
  };

  const selectFirstFile = (curData: any) => {
    const files = curData?.filter((i: any) => i.isLeaf && !i.key?.includes('9999'));
    setCurSameLevelFiles(files || []);
    if (files && files.length) {
      const path = getPathByKey(directoryData, files[0]?.key) + `/${files[0]?.title}`;
      fetchFile(path);
      setSelectedKeys([files[0]?.key]);
    } else {
      setSelectedKeys([]);
      setCurFileType('directory');
    }
  };

  useEffect(() => {
    if (directoryData.length) {
      selectFirstFile(newData.length ? newData : directoryData);
    }
  }, [directoryData, newData]);

  useEffect(() => {
    fetchDirectory('');
    setMaxHeight(document.body.offsetHeight - 250);

    window.onresize = throttle(() => {
      setMaxHeight(document.body.offsetHeight - 250);
    })
  }, []);

  const loadData = (props: any) => {
    const { key, children, title } = props;
    const path = getPathByKey(directoryData, key) + `/${title}`;
    return new Promise<void>(resolve => {
      if (children) {
        resolve();
        return;
      }
      fetchDirectory(path).then((val: any) => {
        const newData = val?.map((i: any, index: number) => ({
          ...i,
          key: `${key}-${i?.key === '9999' ? '9999' : index}`,
        }));
        setNewData(newData);
        // selectFirstFile(newData);
        setDirectoryData(origin => updateTreeData(origin, key, newData));
        resolve();
      });
    });
  };

  const fetchFile = async (path: string) => {
    try {
      const res = await getFile(dataSetId, path);
      if (res && res.code === 0) {
        setCurFile(res.data);
        const suffix = getFileSuffix(res.data?.name);
        if (IMAGE_SUFFIX.includes(suffix)) {
          setCurFileType('image');
        } else {
          setCurFileType('file');
        }
      }
    } catch (err) {
      console.log(err);
    }
  };

  const onFileSelect = (selectedKeys: React.Key[], props: any) => {
    const { node: { title }, selected } = props;
    setSelectedKeys(selectedKeys);
    if (selected) {
      const path = getPathByKey(directoryData, selectedKeys[0]) + `/${title}`;
      fetchFile(path);
      // 获取当前层级的所有文件（文件夹除外）
      const sameLevelFiles = getSameLevelFilesByKey(directoryData, selectedKeys[0]);
      setCurSameLevelFiles(sameLevelFiles);
    } else {
      setCurFileType('directory');
      setCurSameLevelFiles([]);
    }
  };

  useEffect(() => {
    const pressFileTypes = ['image', 'file'];
    if (pressFileTypes.includes(curFileType)) {
      leftPress && onFileIndexChange('prev');
      rigthPress && onFileIndexChange('next');
    }
  }, [leftPress, rigthPress]);

  const onFileIndexChange = (type: 'prev' | 'next') => {
    const curIndex = curSameLevelFiles.findIndex(i => i.key === selectedKeys[0]);
    const newIndex = type === 'prev' ? curIndex - 1 : curIndex + 1;
    const newFile = curSameLevelFiles[newIndex];
    if (newFile && newFile.key !== undefined && newFile.title) {
      const path = getPathByKey(directoryData, newFile.key) + `/${newFile.title}`;
      fetchFile(path);
      setSelectedKeys([newFile.key]);
    } else {
      message.warning(f({ id: `dataSet.detail.files.image.${type}.tips` }));
    }
  };

  return (
    <PageHeaderWrapper onBack={() => history.push(`/dataManage/dataSet/detail/${dataSetId}`)}>
      <Card className={styles.card}>
        <div className={styles.treeBox} style={{ height: maxHeight }}>
          <Tree
            loadData={loadData}
            treeData={directoryData}
            // showIcon
            showLine
            onSelect={onFileSelect}
            selectedKeys={selectedKeys}
          // switcherIcon
          />
        </div>
        <div className={styles.viewFileBox} style={{ height: maxHeight }}>
          {curFileType === 'directory' &&
            <Empty description={f({ id: 'dataSet.detail.files.tips' })} className={styles.empty} />
          }
          {curFileType === 'image' &&
            <ImageViewer
              imgInfo={curFile}
              onFileIndexChange={onFileIndexChange}
              prev={curSameLevelFiles.findIndex(i => i.key === selectedKeys[0]) !== 0}
              next={curSameLevelFiles.findIndex(i => i.key === selectedKeys[0]) !== curSameLevelFiles.length - 1}
            />
          }
          {curFileType === 'file' &&
            <FileViewer
              fileInfo={curFile}
              onFileIndexChange={onFileIndexChange}
              prev={curSameLevelFiles.findIndex(i => i.key === selectedKeys[0]) !== 0}
              next={curSameLevelFiles.findIndex(i => i.key === selectedKeys[0]) !== curSameLevelFiles.length - 1}
            />
          }
        </div>
      </Card>
    </PageHeaderWrapper>
  )
}

export default connect()(Files);